﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Configuration;

namespace Music2SD
{
  public partial class frmMain: Form
  {

    #region Core code

    bool TaskRunning { get; set; }

    const int MaxFilenameLength = 10;

    public const int MB = 1048576;

    public frmMain()
    {
      InitializeComponent();

      txtSource.Text = GetConfig("source");

      txtFormat.Text = GetConfig("format");

      txtTarget.Text = GetConfig("target");
    }

    void ResetControls(string stopMessage = "Stopped")
    {
      TaskRunning = !TaskRunning;

      if (TaskRunning)
      {
        txtSource.Enabled = txtFormat.Enabled = txtTarget.Enabled = false;

        btnWork.Text = "Stop transmission";

        btnWork.ForeColor = Color.Red;
      }
      else
      {
        txtSource.Enabled = txtFormat.Enabled = txtTarget.Enabled = true;

        btnWork.Text = "Start transmission";

        btnWork.ForeColor = Color.Green;

        //progressBar.Value = 0;

        statusLabel.Text = stopMessage;
      }
    }

    void StartSend()
    {
      statusLabel.Text = "Searching files...";

      var directories = GetFileDirectory();

      var formats = GetFileFormat();

      //var searchPattern = GetSearchPattern(formats);

      var files = GetFiles(directories, formats);

      if (files.Count == 0)
      {
        Text = "Music2SD";

        progressBar.Value = 0;

        ResetControls("No files");

        return;
      }

      var filesCount = files.Count.ToString("N0");

      statusLabel.Text = string.Format("{0} files Start sending", filesCount);

      progressBar.Maximum = files.Count;

      var target = txtTarget.Text.Trim();

      int idx = 1;

      foreach (var file in files)
      {
        if (!TaskRunning)
        {
          break;
        }

        Text = string.Format("Music2SD - [{0}/{1}]", idx.ToString("N0"), filesCount);

        TryTransferFile(file, target);

        progressBar.Value = idx;

        idx++;
      }

      if (idx > files.Count)
      {
        ResetControls("Finished");
      }

    }

    void TryTransferFile(string sourceFileName, string target)
    {
      string filename = Path.GetFileName(sourceFileName);

      string destFileName = Path.Combine(target, filename);

      string shortSourceFileName = GetShortFileName(sourceFileName);

      if (File.Exists(destFileName))
      {
        string message = string.Format("Skip: {0}", shortSourceFileName);

        PopMessage(message);
      }
      else
      {
        try
        {
          //PopMessage("Transfer: " + shortSourceFileName);

          DateTime time1 = DateTime.Now;

          TransferFile(sourceFileName, target, filename);

          DateTime time2 = DateTime.Now;

          var fileInfo = new FileInfo(sourceFileName);

          var fileSize = fileInfo.Length/MB;

          var timeSpan = time2 - time1;

          var speed = Math.Round(fileSize / timeSpan.TotalMilliseconds * 1000, 2);

          string message = string.Format("{0} {1}MB {2}MB/s", shortSourceFileName, fileSize.ToString("N2"), speed.ToString("N2"));

          PopMessage(message);

        }
        catch (Exception exc)
        {
          PopMessage(exc.Message);
        }
      }
    }

    void TransferFile(string sourceFileName, string target, string filename)
    {
      string tempDestFileName = Path.Combine(target, filename + "_temp");

      File.Copy(sourceFileName, tempDestFileName, true);

      string destFileName = Path.Combine(target, filename);

      File.Move(tempDestFileName, destFileName);
    }

    string GetShortFileName(string filename)
    {
      return Path.GetFileName(filename);

      //var bytesLength = Encoding.UTF8.GetBytes(filename.ToCharArray()).Length;

      //if (bytesLength > MaxFilenameLength)
      //{
      //  return filename.Substring(0, MaxFilenameLength - 3) + "...";
      //}
      //else
      //{
      //  return filename;
      //}
    }

    void PopMessage(string message)
    {
      if (TaskRunning)
      {
        statusLabel.Text = message;
      }

      //if (string.IsNullOrEmpty(txtResult.Text))
      //{
      //  txtResult.Text = message;
      //}
      //else
      //{
      //  txtResult.Text = message + Environment.NewLine + txtResult.Text;
      //}
    }

    List<string> GetFiles(string[] directories, string[] formats)
    {
      List<string> files = new List<string>();

      foreach (var directory in directories)
      {
        foreach (var format in formats)
        {
          try
          {
            var subFiles = Directory.GetFiles(directory, format, SearchOption.TopDirectoryOnly);

            files.AddRange(subFiles);
          }
          catch (Exception exc)
          {
            PopMessage(exc.Message);
          }
        }
      }

      return files;
    }

    string[] GetFileDirectory()
    {
      return txtSource.Text
        .Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
        .Select(d => d.Trim())
        .ToArray();

    }

    string[] GetFileFormat()
    {
      string[] formats = txtFormat.Text
        .Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
        .Select(d => d.Trim())
        .ToArray();

      return formats;

    }

    string GetSearchPattern(string[] formats)
    {
      string searchPattern = string.Format("({0})", string.Join("|", formats));

      return searchPattern;

    }

    string GetConfig(string key)
    {
      return ConfigurationManager.AppSettings[key];
    }

    void SetConfig(string key, string text)
    {
      var exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;

      var configuration = ConfigurationManager.OpenExeConfiguration(exePath);

      //取得AppSetting节
      var appSection = configuration.AppSettings;

      //var xmlValue = string.Format("<![CDATA[{0}]]>", text.Trim());

      //赋值并保存
      appSection.Settings[key].Value = text.Trim();

      configuration.Save();
    }

    #endregion

    private void btnSend_Click(object sender, EventArgs e)
    {
      ResetControls();

      if (TaskRunning)
      {
        Task.Factory.StartNew(StartSend);
      }
    }

    private void txtTarget_TextChanged(object sender, EventArgs e)
    {
      btnWork.Enabled = Directory.Exists(txtTarget.Text.Trim());

      if (btnWork.Enabled)
      {
        btnWork.ForeColor = TaskRunning ? Color.Red : Color.Green;
      }
      else
      {
        btnWork.ForeColor = Color.Gray;
      }
    }

    private void txtTarget_MouseClick(object sender, MouseEventArgs e)
    {
      txtTarget.Select();

      txtTarget_TextChanged(null, null);
    }

    private void txtSource_MouseLeave(object sender, EventArgs e)
    {
      SetConfig("source", txtSource.Text);
    }

    private void txtFormat_MouseLeave(object sender, EventArgs e)
    {
      SetConfig("format", txtFormat.Text);
    }

    private void txtTarget_MouseLeave(object sender, EventArgs e)
    {
      SetConfig("target", txtTarget.Text);
    }
  }
}